/**
 * @file lj_ringbuffer_print.c
 * @author Liu Bingyi (cecillearfa@163.com)
 * @brief
 * @version 0.1
 * @date 2023-08-21
 *
 * @copyright Copyright (c) 2023 Liu Bingyi
 *  lj-ringbuffer is licensed under Mulan PubL v2.
 *  You can use this software according to the terms and conditions of the Mulan PubL v2.
 *  You may obtain a copy of Mulan PubL v2 at:
 *           http://license.coscl.org.cn/MulanPubL-2.0
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 *  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 *  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  See the Mulan PubL v2 for more details.
 *
 *
 *                      Mulan Public License，Version 2
 *
 *  Mulan Public License，Version 2 (Mulan PubL v2)
 *
 *  May 2021 http://license.coscl.org.cn/MulanPubL-2.0
 *
 */

#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

#include "lj_ringbuffer_print.h"

#define print_buff_frame(contain, property) print_add_frame(contain, PRINT_BUFF_LEN, property)

size_t print_add_frame(const char* contain, size_t width, int property)
{
    const int default_padding = 4;

    size_t contain_length = strlen(contain);

    assert(contain_length != 0);

    size_t front_padding = default_padding;
    size_t rear_padding = default_padding;
    size_t omit = 0;
    size_t str_width = 0;
    size_t row_width = width + 2 * default_padding;

    if (contain_length <= width) {
        front_padding = ((row_width - contain_length) / 2);
        rear_padding = (row_width - contain_length) % 2 ? front_padding + 1 : front_padding;
        str_width = contain_length;
    } else {
        omit = 3;
        str_width = width - omit;
    }

    if (property == title)
        putchar('\n');

    if (property != text) {
        putchar('+');
        for (size_t i = 0; i < row_width; i++) {
            putchar('-');
        }
        putchar('+');
        putchar('\n');
    }

    putchar('|');
    for (size_t i = 0; i < front_padding; i++) {
        putchar(' ');
    }

    for (size_t i = 0; i < str_width; i++) {
        putchar(*(contain + i));
    }

    if (omit > 0) {
        printf("...");
    }

    for (size_t i = 0; i < rear_padding; i++) {
        putchar(' ');
    }
    putchar('|');
    putchar('\n');

    if (property != text) {
        putchar('+');
        for (size_t i = 0; i < row_width; i++) {
            putchar('-');
        }
        putchar('+');
        putchar('\n');
    }
    if (property == footer)
        putchar('\n');

    return contain_length;
}

int print_buffer(const BUFFER_TYPE* buf, size_t length, const char* buf_name)
{
    char str[PRINT_BUFF_LEN + 1] = { 0 };
    sprintf(str, "%s start", buf_name);
    print_buff_frame(str, title);

    for (size_t i = 0; i < length; i++) {
        BUFFER_TO_STRING(str, sizeof(str), &buf[i]);
        print_buff_frame(str, text);
    }

    sprintf(str, "%s end", buf_name);
    print_buff_frame(str, footer);

    return 0;
}

int print_ringbuffer(const lj_ringbuffer_t ring)
{
    char str[100] = { 0 };
    size_t str_len = sprintf(str, "ring startrindex=%zu,rmirror=%d,windex=%zu,wmirror=%d",
        ring.rb_r_index, ring.rb_r_mirror, ring.rb_w_index, ring.rb_w_mirror);

    print_add_frame("ring start", str_len, title);
    print_add_frame(str, str_len, text);

    for (size_t i = 0; i < ring.buffer_size; i++) {
        BUFFER_TO_STRING(str, sizeof(str), &ring.buffer[i]);
        print_add_frame(str, str_len, text);
    }
    print_add_frame("ring end", str_len, footer);

    return 0;
}

int print_sync_ringbuffer(const lj_ringbuffer_sync_t ring)
{
    char str[100] = { 0 };
    size_t str_len = sprintf(str, "ring startrindex=%zu,rmirror=%d,windex=%zu,wmirror=%d",
        ring.rb_r_index, ring.rb_r_mirror, ring.rb_w_index, ring.rb_w_mirror);

    print_add_frame("ring start", str_len, title);
    print_add_frame(str, str_len, text);

    for (size_t i = 0; i < ring.buffer_size; i++) {
        BUFFER_TO_STRING(str, sizeof(str), &ring.buffer[i]);
        print_add_frame(str, str_len, text);
    }
    print_add_frame("ring end", str_len, footer);

    return 0;
}

#include <pthread.h>
int print_buffer_sync(const BUFFER_TYPE* buf, size_t length, const char* buf_name)
{
    static pthread_mutex_t outfd = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_lock(&outfd);

    char str[PRINT_BUFF_LEN + 1] = { 0 };
    sprintf(str, "%s start", buf_name);
    print_buff_frame(str, title);

    for (size_t i = 0; i < length; i++) {
        BUFFER_TO_STRING(str, sizeof(str), &buf[i]);
        print_buff_frame(str, text);
    }

    sprintf(str, "%s end", buf_name);
    print_buff_frame(str, footer);
    pthread_mutex_unlock(&outfd);

    return 0;
}